﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CmdCreateStructureInstanceByPick.h"
#include "CmdStatusUtils.h"
#include "StructureFamilyUiUtils.h"
#include "StructureFamilyUtils.h"
#include "StructureCmdParamIds.h"
#include "CommandParameters.h"
#include "IDocument.h"
#include "IFamily.h"
#include "IUserTransaction.h"
#include "IInstance.h"
#include "IInstanceType.h"
#include "StructureInstancePresetParameterUtils.h"
#include "IPropertyPanelEventArgs.h"
#include "PropertyWidgetUtils.h"
#include "ActionDrawCurveByPickCreator.h"
#include "GcmpActionBase.h"
#include "GbmpPresetParameterUIUtils.h"
#include "PickCurveDrawElementBehavior.h"
#include "IActionInputEventArgs.h"
#include "UiDocumentViewUtils.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

CmdCreateStructureInstanceByPick::CmdCreateStructureInstanceByPick(const std::wstring& commandId)
    : GbmpCommandBase(commandId)
{
}

bool CmdCreateStructureInstanceByPick::IsEnabled() const
{
    CMD_ONLY_ENABLE_IN_PROJECT_ENVIRONMENT
}

bool CmdCreateStructureInstanceByPick::IsVisible() const
{
    CMD_ONLY_VISIBLE_IN_PROJECT_ENVIRONMENT
}

bool CmdCreateStructureInstanceByPick::ResetCommand()
{
    m_familyId = ElementId::InvalidID;
    m_instanceTypeId = ElementId::InvalidID;
    m_pPickCurveAction = nullptr;

    return true;
}

OwnerPtr<IAction> CmdCreateStructureInstanceByPick::ExecuteCommand(const CommandParameters& cmdParams)
{
    bool bOk = this->OnExecuteCommand();
    if (!bOk)
        return nullptr;

    bOk = this->ResetCommand();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"ResetCommand失败",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    // 创建内建族
    StructureFamilyUiUtils::FamilyCreators defaultFamilyCreators = this->GetDefaultFamilyCreators();
    StructureFamilyUiUtils::CreateFamilies(pDoc, defaultFamilyCreators);

    // 获取新创建实例的族名称、实例类型
    std::wstring familyName;
    std::wstring instanceType;
    {
        // 从命令参数读取
        auto itr = cmdParams.find(ID_CMD_PARAM_FAMILY_NAME);
        if (itr != cmdParams.end())
        {
            familyName = itr->second.AsWString();
        }
        itr = cmdParams.find(ID_CMD_PARAM_INSTANCE_TYPE);
        if (itr != cmdParams.end())
        {
            instanceType = itr->second.AsWString();
        }
    }
    if (familyName.empty() || instanceType.empty())
    {
        StructureInstancePresetParameterUtils::GetPresetFamilyNameAndInstanceType(pDoc, this->GetCategory(), this->GetCategorySecondKey(), familyName, instanceType);
    }
    if (familyName.empty())
    {
        familyName = this->GetDefaultFamilyName();
    }
    const IFamily* pFamily = IFamily::GetFamilyByName(pDoc, familyName);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFamily, L"pFamily为空",L"GDMPLab",L"2024-03-30");

    if (instanceType.empty())
    {
        bOk = StructureFamilyUtils::GetFirstInstanceType(pFamily, instanceType);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"GetFirstInstanceType失败",L"GDMPLab",L"2024-03-30");
    }
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(!instanceType.empty(), L"instanceType为空",L"GDMPLab",L"2024-03-30");

    const IInstanceType* pInstanceType = pFamily->GetInstanceTypeByName(instanceType);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstanceType, L"pInstanceType为空",L"GDMPLab",L"2024-03-30");

    this->SetFamilyIdAndInstanceTypeId(pFamily->GetElementId(), pInstanceType->GetElementId());

    // 配置Action
    OwnerPtr<PickCurveDrawElementBehavior> opPickBehavior = this->CreateActionDrawCurvePickBehavior();
    opPickBehavior->SetOnInitActionCallback(PickCurveDrawElementBehavior::CreateOnInitActionCallback(&CmdCreateStructureInstanceByPick::OnInitAction, this));
    opPickBehavior->SetOnDestroyActionCallback(PickCurveDrawElementBehavior::CreateOnDestroyActionCallback(&CmdCreateStructureInstanceByPick::OnDestroyAction, this));
    opPickBehavior->SetOnPropertyPanelEventCallback(PickCurveDrawElementBehavior::CreateOnPropertyPanelEventCallback(&CmdCreateStructureInstanceByPick::OnPropertyPanelEvent, this));
    // ActionInputDlg 相关的回调函数
    opPickBehavior->SetDefineInputDialogCallback(PickCurveDrawElementBehavior::CreateDefineInputDialogCallback(&CmdCreateStructureInstanceByPick::DefineInputDialog, this));
    opPickBehavior->SetOnActionInputEventCallback(PickCurveDrawElementBehavior::CreateOnActionInputEventCallback(&CmdCreateStructureInstanceByPick::OnActionInputEvent, this));

    OwnerPtr<ActionDrawCurveByPickInput> pickCurveActionInput = NEW_AS_OWNER_PTR(ActionDrawCurveByPickInput, TransferOwnership(opPickBehavior));
    OwnerPtr<IAction> opPickCurveAction = ActionDrawCurveByPickCreator::Create(TransferOwnership(pickCurveActionInput));
    m_pPickCurveAction = dynamic_cast<GcmpActionBase*>(opPickCurveAction.get());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pPickCurveAction, L"m_pPickCurveAction为空",L"GDMPLab",L"2024-03-30");
    m_pPickCurveAction->SetCommandId(this->GetCommandId());

    return TransferOwnership(opPickCurveAction);
}

bool CmdCreateStructureInstanceByPick::OnInitAction(IUiView* pCurrentView)
{
    // 更新属性面板
    ElementId presetElementId;
    bool bOk = this->CreatePresetElement(presetElementId);
    if (bOk)
    {
        m_pPickCurveAction->SetPreSetElementId(presetElementId);
        GbmpPresetParameterUIUtils::UpdatePropertyPanel(presetElementId);
        GbmpPresetParameterUIUtils::EnablePropertyPanel(true);
    }

    // 设置Ribbon上下文面板
    this->SetupRibbonContextualPanel();

    return true;
}

bool CmdCreateStructureInstanceByPick::OnDestroyAction()
{
    GbmpPresetParameterUIUtils::UpdatePropertyPanel(ElementId::InvalidID);
    GbmpPresetParameterUIUtils::EnablePropertyPanel(true);

    return true;
}

bool CmdCreateStructureInstanceByPick::OnCurvePreview(IUiView* pCurrentView, OwnerPtr<ICurve2d> opCurve2d, OwnerPtr<IGraphicsNodeGroup>& opPreviewGraphics)
{
    return false;
}

bool CmdCreateStructureInstanceByPick::OnPropertyPanelEvent(IPropertyPanelEventArgs* pArgs)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pArgs, L"pArgs为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    // TODO: 接口
    if (PropertyWidgetUtils::IsComponentTypeChangedEvent(pArgs->GetPropertyItemUniqueId()))
    {
        ElementId newInstanceTypeId(StringUtil::ToNumber<Int64>(pArgs->GetNewValue()));
        DBG_WARN_AND_RETURN_FALSE_UNLESS(newInstanceTypeId.IsValid(), L"newInstanceTypeId无效",L"GDMPLab",L"2024-03-30");

        ElementId newFamilyId;
        bool bOk = StructureFamilyUtils::GetFamilyIdByTypeId(pDoc, newInstanceTypeId, newFamilyId);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(bOk, L"GetFamilyNameByTypeId失败",L"GDMPLab",L"2024-03-30");

        if (m_familyId.HasSameValue(newFamilyId) && m_instanceTypeId.HasSameValue(newInstanceTypeId))
            return true;

        this->SetFamilyIdAndInstanceTypeId(newFamilyId, newInstanceTypeId);
    }

    return true;
}

bool CmdCreateStructureInstanceByPick::DefineInputDialog(DefineInputDialogParams& inputItems)
{
    return false;
}

bool CmdCreateStructureInstanceByPick::OnActionInputEvent(IActionInputEventArgs* pArgs)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pArgs, L"pArgs为空",L"GDMPLab",L"2024-03-30");
    return false;
}

bool CmdCreateStructureInstanceByPick::SetFamilyIdAndInstanceTypeId(ElementId familyId, ElementId instanceTypeId)
{
    if (m_familyId.HasSameValue(familyId) && m_instanceTypeId.HasSameValue(instanceTypeId))
        return true;

    m_familyId = familyId;
    m_instanceTypeId = instanceTypeId;

    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IUserTransaction> opTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"保存当前创建实例的族类型到预设参数"), true);

    bool bOk = StructureInstancePresetParameterUtils::SetPresetInstanceType(pDoc, this->GetCategory(), this->GetCategorySecondKey(), m_instanceTypeId);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(bOk, L"SetPresetInstanceType失败",L"GDMPLab",L"2024-03-30");

    opTransaction->Commit();

    return true;
}
